home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / icmpcmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  6.2 KB  |  277 lines

  1. /* ICMP-related user commands */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "icmp.h"
  5. #include "mbuf.h"
  6. #include "netuser.h"
  7. #include "internet.h"
  8. #include "timer.h"
  9. #include "socket.h"
  10. #include "proc.h"
  11. #include "session.h"
  12. #include "cmdparse.h"
  13. #include "commands.h"
  14. #include "config.h"
  15.  
  16. static int doicmpec __ARGS((int argc, char *argv[],void *p));
  17. static int doicmpstat __ARGS((int argc, char *argv[],void *p));
  18. static int doicmptr __ARGS((int argc, char *argv[],void *p));
  19. static void pingtx __ARGS((int s,void *ping1,void *p));
  20.  
  21. static struct cmds Icmpcmds[] = {
  22.     "echo",        doicmpec,    0, 0, NULLCHAR,
  23.     "trace",    doicmptr,    0, 0, NULLCHAR,
  24.     NULLCHAR
  25. };
  26.  
  27. int Icmp_trace;
  28. static int Icmp_echo = 1;
  29.  
  30. int
  31. doicmp(argc,argv,p)
  32. int argc;
  33. char *argv[];
  34. void *p;
  35. {
  36.     if(argc == 1)
  37.         return doicmpstat(argc,argv,p);
  38.     return subcmd(Icmpcmds,argc,argv,p);
  39. }
  40.  
  41. static int
  42. doicmpstat(argc,argv,p)
  43. int argc;
  44. char *argv[];
  45. void *p;
  46. {
  47.     register int i;
  48.     int lim;
  49.  
  50.     /* Note that the ICMP variables are shown in column order, because
  51.      * that lines up the In and Out variables on the same line
  52.      */
  53.     lim = NUMICMPMIB/2;
  54.     for(i=1;i<=lim;i++){
  55.         tprintf("(%2u)%-20s%10lu",i,Icmp_mib[i].name,
  56.          Icmp_mib[i].value.integer);
  57.         tprintf("     (%2u)%-20s%10lu\n",i+lim,Icmp_mib[i+lim].name,
  58.          Icmp_mib[i+lim].value.integer);
  59.     }
  60.     return 0;
  61. }
  62. static int
  63. doicmptr(argc,argv,p)
  64. int argc;
  65. char *argv[];
  66. void *p;
  67. {
  68.     return setbool(&Icmp_trace,"ICMP tracing",argc,argv);
  69. }
  70. static int
  71. doicmpec(argc,argv,p)
  72. int argc;
  73. char *argv[];
  74. void *p;
  75. {
  76.     return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
  77. }
  78.  
  79. /* Send ICMP Echo Request packets */
  80. int
  81. doping(argc,argv,p)
  82. int argc;
  83. char *argv[];
  84. void *p;
  85. {
  86.     struct proc *pinger = NULLPROC;    /* Transmit process */
  87.     struct sockaddr_in from;
  88.     struct icmp icmp;
  89.     struct mbuf *bp;
  90.     int32 timestamp,rtt,abserr;
  91.     int s,fromlen;
  92.     struct ping ping;
  93.     struct session *sp;
  94.  
  95.     memset((char *)&ping,0,sizeof(ping));
  96.     /* Allocate a session descriptor */
  97.     if((sp = ping.sp = newsession(argv[1],PING)) == NULLSESSION){
  98.         tprintf("Too many sessions\n");
  99.         freeargs(argc,argv);
  100.         return 1;
  101.     }
  102.     if((sp->s = s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) == -1){
  103.         tprintf("Can't create socket\n");
  104.         freeargs(argc,argv);
  105.         keywait(NULLCHAR,1);
  106.         freesession(sp);
  107.         return 1;
  108.     }
  109.     tprintf("Resolving %s... ",sp->name);
  110.     if((ping.target = resolve(sp->name)) == 0){
  111.         tprintf(Badhost,sp->name);
  112.         freeargs(argc,argv);
  113.         keywait(NULLCHAR,1);
  114.         freesession(sp);
  115.         return 1;
  116.     }
  117.     if(argc > 2)
  118.         ping.len = atoi(argv[2]);
  119.  
  120.     if(argc > 3)
  121.         ping.interval = atol(argv[3]);
  122.  
  123.     /* This is a hack. If the specified interval is less than one tick,
  124.      * assume it to be in seconds. Otherwise assume milliseconds.
  125.      */
  126.     if(ping.interval < MSPTICK)
  127.         ping.interval *= (1000 / MSPTICK);
  128.     else
  129.         ping.interval /= MSPTICK;
  130.  
  131.     /* Optionally ping a range of IP addresses */
  132.     if(argc > 4)
  133.         ping.incflag = 1;
  134.  
  135.     freeargs(argc,argv);
  136.     if(ping.interval != 0){
  137.         pinger = newproc("pingtx",300,pingtx,s,&ping,NULL);
  138.     } else {
  139.         /* One shot ping; let echo_proc hook handle response.
  140.          * An ID of MAXINT16 will not be confused with a legal socket
  141.          * number, which is used to identify repeated pings
  142.          */
  143.         pingem(s,ping.target,0,MAXINT16,ping.len);
  144.         freesession(sp);
  145.         return 0;
  146.     }
  147.     /* Now collect the replies */
  148.     for(;;){
  149.         fromlen = sizeof(from);
  150.         if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1)
  151.             break;
  152.         ntohicmp(&icmp,&bp);
  153.         if(icmp.type != ICMP_ECHO_REPLY
  154.          || icmp.args.echo.id != s){
  155.             /* Ignore other people's responses */
  156.             free_p(bp);
  157.             continue;
  158.         }
  159.         ping.responses++;
  160.         /* Get stamp */
  161.         if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
  162.          != sizeof(timestamp)){
  163.             /* The timestamp is missing! */
  164.             free_p(bp);    /* Probably not necessary */
  165.             continue;
  166.         }
  167.         free_p(bp);
  168.  
  169.         /* Compute round trip time, update smoothed estimates */
  170.         rtt = (Clock - timestamp) * MSPTICK;
  171.         if(ping.incflag){
  172.             tprintf("%s: rtt %lu\n",inet_ntoa(from.sin_addr.s_addr),
  173.              rtt);
  174.             continue;
  175.         }
  176.         abserr = rtt > ping.srtt ? rtt - ping.srtt : ping.srtt - rtt;
  177.  
  178.         if(ping.responses == 1){
  179.             /* First response, base entire SRTT on it */
  180.             ping.srtt = rtt;
  181.         } else {
  182.             ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
  183.         }
  184.         ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
  185.  
  186.     }
  187.     if(pinger != NULLPROC)
  188.         killproc(pinger);
  189.     freesession(sp);
  190.     return 0;
  191. }
  192. void
  193. echo_proc(source,dest,icmp,bp)
  194. int32 source;
  195. int32 dest;
  196. struct icmp *icmp;
  197. struct mbuf *bp;
  198. {
  199.     int32 timestamp,rtt;
  200.  
  201.     if(Icmp_echo && icmp->args.echo.id == MAXINT16
  202.      && pullup(&bp,(char *)×tamp,sizeof(timestamp))
  203.      == sizeof(timestamp)){
  204.         /* Compute round trip time */
  205.         rtt = (Clock - timestamp) * MSPTICK;
  206.         tprintf("%s: rtt %lu\n",inet_ntoa(source),rtt);
  207.     }
  208.     free_p(bp);
  209. }
  210. /* Ping transmit process. Runs until killed */
  211. static void
  212. pingtx(s,ping1,p)
  213. int s;        /* Socket to use */
  214. void *ping1;
  215. void *p;
  216. {
  217.     struct ping *ping;
  218.  
  219.     ping = (struct ping *)ping1;
  220.     ping->sent = 0;
  221.     if(ping->incflag){
  222.         for(;;){
  223.             tprintf("pinging %s\n",inet_ntoa(ping->target));
  224.             pingem(s,ping->target++,0,(int16)s,ping->len);
  225.             pause(ping->interval);
  226.         }
  227.     } else {
  228.         for(;;){
  229.             tprintf("pinging %s: sent %lu rcvd %lu avg rtt %lu mdev %lu\n",
  230.              ping->sp->name,ping->sent,ping->responses,ping->srtt,
  231.              ping->mdev);
  232.             pingem(s,ping->target,(int16)ping->sent++,(int16)s,ping->len);
  233.             pause(ping->interval);
  234.         }
  235.     }
  236. }
  237.  
  238.  
  239. /* Send ICMP Echo Request packet */
  240. int
  241. pingem(s,target,seq,id,len)
  242. int s;        /* Raw socket on which to send ping */
  243. int32 target;    /* Site to be pinged */
  244. int16 seq;    /* ICMP Echo Request sequence number */
  245. int16 id;    /* ICMP Echo Request ID */
  246. int16 len;    /* Length of optional data field */
  247. {
  248.     struct mbuf *data;
  249.     struct mbuf *bp;
  250.     struct icmp icmp;
  251.     struct sockaddr_in to;
  252.  
  253.     if((data = alloc_mbuf((int16)(len+sizeof(Clock)))) == NULLBUF)
  254.         return -1;
  255.     data->cnt = len+sizeof(Clock);
  256.     /* Set optional data field, if any, to all 55's */
  257.     if(len != 0)
  258.         memset(data->data+sizeof(Clock),0x55,len);
  259.  
  260.     /* Insert timestamp and build ICMP header */
  261.     memcpy(data->data,(char *)&Clock,sizeof(Clock));
  262.     icmpOutEchos++;
  263.     icmpOutMsgs++;
  264.     icmp.type = ICMP_ECHO;
  265.     icmp.code = 0;
  266.     icmp.args.echo.seq = seq;
  267.     icmp.args.echo.id = id;
  268.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  269.         free_p(data);
  270.         return 0;
  271.     }
  272.     to.sin_family = AF_INET;
  273.     to.sin_addr.s_addr = target;
  274.     send_mbuf(s,bp,0,(char *)&to,sizeof(to));
  275.     return 0;
  276. }
  277.